// -*-mode:c++; coding:utf-8-*-

#include "logger.hpp"

#include "async_write.hpp"
#include "root_meta_cache.hpp"

namespace xbase
{
	void root_meta_cache::on_async_get_root_meta(handler_type handler, bool hard)
	{
		error_code ec;

		if (!hard && m_root_meta_got)
		{
			this->get_upper_level_service().dispatch(boost::bind(handler, ec));
		}
		else
		{
			// 异步获得根子表信息
			request_packet_ptr pkt_ptr(new request_packet_type());
			bool is_requesting = (!m_handler_list.empty());
			m_handler_list.push_back(handler);

			if (!is_requesting)
			{
				xbase::async_write(m_session_manager, m_master_server_endpoint, pkt_ptr,
					this->get_lower_level_service().wrap(
					boost::bind(&this_type::on_get_root_meta_response, this_ptr(), _1, _2)
					)
					);
			}
		}
	}

	void root_meta_cache::on_get_root_meta_response(protocol::packet_ptr pkt_ptr, const error_code &ec)
	{
		if (!ec)
		{
			response_packet_type *p = boost::polymorphic_downcast<response_packet_type*>(pkt_ptr.get());

			const protocol::root_meta_response &resp = p->body();

			m_root_tablet_info = resp.m_tablet;
			m_root_server_addr = resp.m_server_address;

			unsigned tablet_status = m_root_tablet_info.m_status;
			if (TabletStatusGetOnline(tablet_status))
			{
				m_retry_times = 0;

				m_root_meta_got = true;

				while (!m_handler_list.empty())
				{
					handler_type handler = m_handler_list.front();
					this->get_upper_level_service().dispatch(boost::bind(handler, ec));
					m_handler_list.pop_front();
				}
			}
			else
			{
				on_fail(xbase::error::root_meta_not_loaded);
			}
		}
		else
		{
			m_root_meta_got = false;
			on_fail(ec);
		}
	}

	void root_meta_cache::on_retry()
	{
		request_packet_ptr pkt_ptr(new request_packet_type());

		xbase::async_write(m_session_manager, m_master_server_endpoint, pkt_ptr,
			boost::bind(&this_type::on_get_root_meta_response, this_ptr(), _1, _2));
	}

	void root_meta_cache::on_fail(const error_code &ec)
	{
		if(m_options.can_retry(m_retry_times))
		{
			LOG(WARN, "retry: " << ec << " - " << ec.message()
				<< ", retry_times = " << m_retry_times);

			++ m_retry_times;
			if(!m_timer)
				m_timer.reset(new boost::asio::deadline_timer(this->get_lower_level_service()));

			m_timer->expires_from_now(m_options.get_retry_interval());
			m_timer->async_wait(boost::bind(&this_type::on_retry, this_ptr()));
		}
		else
		{
			on_error(ec);
		}
	}

	void root_meta_cache::on_error(const error_code &ec)
	{
		LOG(ERROR, "error: " << ec << " - " << ec.message()
			<< ", retry_times = " << m_retry_times);

		m_retry_times = 0;

		while (!m_handler_list.empty())
		{
			handler_type handler = m_handler_list.front();
			this->get_upper_level_service().dispatch(boost::bind(handler, ec));
			m_handler_list.pop_front();
		}
	}
}
